iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0
Software Development

Rails Active Model系列 第 28

D-28 自定比較規則 - Comparable

  • 分享至 

  • xImage
  •  

Ruby 原生有個 module 很好用,只要 include 他,你就可以自行定義大小比較的規則,在你的世界,誰大誰小你說了算!

這個 module 叫做 Comparable

在 include 他之後,你需要定義你的實體方法 <=> 來控制大小比對的結果。回傳 -1 代表小於,0代表相等,1代表大於。

這可以應用在像是權限判斷或是狀態更新的控制。
這邊以權限判斷為例,假設有三種權限由小到大分別是 訪客、使用者、VIP、管理員

class Role < String # 因為本質是一種字串資料,因此繼承字串
  include Comparable
  AVAILABLES = %w(passenger user vip admin).freeze

  def <=>(another)
    # 這邊範例使用表示權限的字串在 AVAILABLES 裡的位置來進行比對,越後面越大,越前面越小,找不到的最小
    index = AVAILABLES.index(self) || 0
    another_index = AVAILABLES.index(another.to_s) || 0
    index <=> another_index
  end
end

接著我們來測試看看他是否能如筆者所說般進行大小比對。

passenger = Role.new 'passenger'
user = Role.new 'user'
vip = Role.new 'vip'
admin = Role.new 'admin'

admin > passenger # true
passenger > vip # false
vip > user # true
user > admin # false

看起來是完全照預想中運作的!
那麼只要把他帶入 model 的權限欄位像是 user.role 就可以暗渡陳倉,讓這個欄位多出這樣一個比對的功能了!

class User < ApplicationRecord
  def role
    Role.new self[:role]
  end
end

user = User.first
user.role # 假設是 "user"
user.role.class
 => Role # 可以看到其實已經變成是 Role 了
user.role > :admin 
 => false
user.role < :admin
 => true # 成功!

其實在 Rails 的 String 本身就已經幫你裝好了這 module,就沒必要額外再 include了。

而且還不只如此,Rails 有內建一個 class ActiveSupport::StringInquirer 是繼承自 String 的,他更多了個特異功能,只要對他使用 .something? 任何以問號結尾的 method,就會回傳 self == "something" 的結果,相當帥氣。

class Role < ActiveSupport::StringInquirer # 改為繼承自 StringInquirer
  # 其餘一切設定如上
end

# model 設定也如上,此處省略

user = User.first
user.role < :admin
 => true
user.role.user?
 => true
user.role.admin?
 => false

這樣一來,是不是就能讓你的 code 更簡潔易讀了呢?


上一篇
D-27 合理規劃 validation 規則
系列文
Rails Active Model28
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言